package org.slf4j.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;

import com.db.jschool.logging.Appender;
import com.db.jschool.logging.ConsoleAppender;
import com.db.jschool.logging.FileAppender;
import com.db.jschool.logging.Layout;
import com.db.jschool.logging.Level;
import com.db.jschool.logging.helpers.IPropertiesLoader;
import com.db.jschool.logging.helpers.LoggerPropertiesLoader;

public class MyLoggerFactory implements ILoggerFactory {
	
	private static final ConcurrentMap<String, LoggerAdapter> loggers = new ConcurrentHashMap<>();
	private static final ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<>();
	private final Properties properties;
	private static final IPropertiesLoader propertiesLoader = new LoggerPropertiesLoader();
	
	private static final String KEY_PREFIX_LOGGER = "logger";
	private static final String KEY_PREFIX_APPENDER = "appender";
	private static final String KEY_DEFAULT = "default";
	private static final String APPENDER_TYPE_CONSOLE = "console";
	private static final String APPENDER_TYPE_FILE = "file";
	private static final String KEY_SUFFIX_FILE_NAME = "filename";
	private static final String KEY_SUFFIX_LAYOUT = "layout";
	
				
	public MyLoggerFactory() {
		Properties p;
		try {
			p = propertiesLoader.loadProperties();
		} catch (IOException e) {
			System.err.println("Unable to load properties");
			p = new Properties();
		}
		this.properties = p;
	}
	
	@Override
	public synchronized Logger getLogger(String name) {
		name = name.trim();
		if (!loggers.containsKey(name)) {
			loggers.putIfAbsent(name, new LoggerAdapter(createLogger(name)));
		}
		return loggers.get(name);
	}
	
	private Appender getAppender(String name) {
		name = name.trim();
		if (!appenders.containsKey(name)) {
			appenders.putIfAbsent(name, createAppender(name));
		}
		return appenders.get(name);
	}
	
	private com.db.jschool.logging.Logger createLogger(String name) {
		com.db.jschool.logging.Logger logger = new com.db.jschool.logging.Logger(name);
		List<String> values;
		if (properties.containsKey(KEY_PREFIX_LOGGER + "." + name)) {
			values = getListProperty(KEY_PREFIX_LOGGER + "." + name);
		} else if (properties.containsKey(KEY_PREFIX_LOGGER + "." + KEY_DEFAULT)) {
			values = getListProperty(KEY_PREFIX_LOGGER + "." + KEY_DEFAULT);
		} else {
			values = new ArrayList<String>();
			values.add(Level.INFO.toString());
		}
		logger.setLevel(Level.valueOf(values.get(0)));
		for (int i = 1; i < values.size(); i++) {
			logger.addAppender(getAppender(values.get(i)));
		}
		return logger;
	}
	
	private Appender createAppender(String name) {
		String appenderType;
		String targetAppender;
		if (properties.containsKey(targetAppender = KEY_PREFIX_APPENDER + "." + name)) {
			appenderType = properties.getProperty(targetAppender);
		} else if (properties.containsKey(targetAppender = KEY_PREFIX_APPENDER + "." + KEY_DEFAULT)) {
			appenderType = properties.getProperty(targetAppender);
		} else {
			throw new RuntimeException("Unknown appender: " + name);
		}
		
		Appender appender = null;
		try {
			switch (appenderType) {
			case APPENDER_TYPE_CONSOLE:
				appender = new ConsoleAppender(name);
				break;
			case APPENDER_TYPE_FILE:
				String fileName = properties.getProperty(targetAppender + "." + KEY_SUFFIX_FILE_NAME, null);
				if (fileName == null) {
					throw new RuntimeException("\"*.filename\" property isn't defined");
				}
				appender = new FileAppender(name, fileName);
				break;
			default:
				throw new RuntimeException("Unknown appender type: " + appenderType);
			}
			
			appender.setLayout(createLayout(targetAppender));
		} catch (IOException e) {
			e.printStackTrace();
		}
		return appender;
	}
	
	private Layout createLayout(String appender) {
		String targetLayout;
		if (properties.containsKey(targetLayout = appender + "." + KEY_SUFFIX_LAYOUT)) {
			return new Layout(properties.getProperty(targetLayout));
		} else {
			return new Layout();
		}
	}
		
	@SuppressWarnings("unchecked")
	private List<String> getListProperty(String key) {
		String value = properties.getProperty(key, null);
		 
		if (value != null) {
			String[] values = value.split(",");
			return Arrays.asList(values);
		}
		
		return Collections.EMPTY_LIST;
	}

	
}
